package com.bysc.commentservice.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bysc.baseservice.handler.BaiYunException;
import com.bysc.commentservice.client.UserClient;
import com.bysc.commentservice.entity.CommentParent;
import com.bysc.commentservice.entity.CommentSon;
import com.bysc.commentservice.entity.vo.CommentFormVo;
import com.bysc.commentservice.entity.vo.CommentQueryVo;
import com.bysc.commentservice.mapper.CommentParentMapper;
import com.bysc.commentservice.service.CommentParentService;
import com.bysc.commonutils.ResultCode;
import com.bysc.commonutils.constant.MessageConstant;
import com.bysc.commonutils.utils.DateUtil;
import com.bysc.commonutils.vo.PageResult;
import com.bysc.commonutils.vo.UserInfoVo;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.regex.Pattern;

import static com.bysc.commonutils.constant.RedisConstant.*;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author kkk
 * @since 2024-06-15
 */
@Slf4j
@Service
public class CommentParentServiceImpl extends ServiceImpl<CommentParentMapper, CommentParent> implements CommentParentService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private UserClient userClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;



    @Override
    public void updateParentCommentById(CommentFormVo parentCommentFormVo, Object id) {
        String postId = parentCommentFormVo.getPostId();
        // 判空
        if (StringUtils.isEmpty(postId)) {
            throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATECOMMENT_ERROR);
        }
        // 身份检查,只有自己和管理员才能修改
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        query.addCriteria(Criteria.where("postId").is(postId));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        CommentParent one = mongoTemplate.findOne(query, CommentParent.class);
        if (ObjectUtils.isEmpty(one)) {
            throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATECOMMENT_ERROR);
        }
        Update update = new Update();
        update.set("content", parentCommentFormVo.getContent());
        update.set("contentImage", parentCommentFormVo.getContentImage());
        UpdateResult result = null;

        result = mongoTemplate.updateFirst(query, update, CommentParent.class);

        log.info("更新父级评论,详细信息：{}", result);
    }

    @Override
    public CommentParent deleteParentCommentById(Object id) {
// 判空
        if (id == null) {
            throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATECOMMENT_ERROR);
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        CommentParent commentParent = mongoTemplate.findOne(query, CommentParent.class);
        if (commentParent == null) {
            throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATECOMMENT_ERROR);
        }
        Update update = new Update();
        update.set("isDeleted", true);
        UpdateResult remove = null;
        remove = mongoTemplate.updateFirst(query, update, CommentParent.class);
        log.info("删除父级评论,详细信息：{}", remove);
        return commentParent;
    }

    @Override
    public CommentParent addParentCommentByPostIdAndToken(CommentFormVo parentCommentFormVo, String userId) {
        CommentParent commentParent = new CommentParent();
        BeanUtils.copyProperties(parentCommentFormVo, commentParent);
        commentParent.setUserId(userId);
        commentParent.setIsDeleted(false);
        commentParent.setGmtCreate(new Date());
        commentParent.setGmtModified(new Date());
        CommentParent insert = mongoTemplate.insert(commentParent);
        return insert;
    }

    @Override
    public PageResult getAllCommentListByQueryVoOrderByCreatTime(Integer page, Integer limit, CommentQueryVo queryVo) {
        String value = queryVo.getValue();
        String userId = queryVo.getUserId();
        String start = queryVo.getStart();
        String end = queryVo.getEnd();

        Query query = new Query();
        if (!StringUtils.isEmpty(userId)) {
            query.addCriteria(Criteria.where("userId").is(userId));
        }
        query.addCriteria(Criteria.where("isDeleted").is(false));
        if (!StringUtils.isEmpty(start) && StringUtils.isEmpty(end)) { // 只有start
            query.addCriteria(Criteria.where("gmtCreate").gte(DateUtil.dateToISODate(start)));
        } else if (StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) { // 只有end
            query.addCriteria(Criteria.where("gmtCreate").lte(DateUtil.dateToISODate(end)));
        } else if (!StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) { // 有start有end
            query.addCriteria(Criteria.where("gmtCreate").gte(DateUtil.dateToISODate(start))
                    .andOperator(Criteria.where("gmtCreate").lte(DateUtil.dateToISODate(end))));
        }
        if (!StringUtils.isEmpty(value)) {
            Pattern pattern = Pattern.compile("^.*" + value + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("content").regex(pattern));
        }
        //获取总数
        long total = mongoTemplate.count(query, CommentParent.class);

        // 按照最新发布时间降序排序
        Sort sort = Sort.by(Sort.Direction.DESC, "gmtCreate");
        // 分页
        Pageable pageable = PageRequest.of(page - 1, limit, sort);
        query.with(pageable);
        List<CommentParent> commentParents = mongoTemplate.find(query, CommentParent.class);
        //获取评论详细信息
        String setKey = "";
        for (CommentParent commentParent : commentParents) {
            String hashKey = COMMENT_PARENTCOMMENT + commentParent.getId();
            getInfo(commentParent, setKey, hashKey);
        }
        PageResult pageResult = new PageResult(total, commentParents.size(), commentParents, page);
        return pageResult;
    }

    @Override
    public PageResult getCommentListByTokenAndPostIdOrderByCreatTime(String userId, String id, Integer page, Integer limit) {
        Query query = new Query();
        query.addCriteria(Criteria.where("postId").is(id));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        //获取总数
        long total = mongoTemplate.count(query, CommentParent.class);

        // 分页
        // 按照最新发布时间降序排序
        Sort sort = Sort.by(Sort.Direction.DESC, "gmtCreate");
        Pageable pageable = PageRequest.of(page - 1, limit, sort);
        query.with(pageable);
        List<CommentParent> commentParents = mongoTemplate.find(query, CommentParent.class);
        //获取评论详细信息
        String setKey = COMMENT_PARENTCOMMENT_USER_LIKE + userId;
        for (CommentParent commentParent : commentParents) {
            String hashKey = COMMENT_PARENTCOMMENT + commentParent.getId();
            getInfo(commentParent, setKey, hashKey);
        }
        PageResult pageResult = new PageResult(total, commentParents.size(), commentParents, page);
        return pageResult;

    }

    @Override
    public PageResult getCommentListByTokenAndPostIdOrderByLike(String userId, String postId, Integer page, Integer limit) {


        Query query = new Query();
        query.addCriteria(Criteria.where("postId").is(postId));
        query.addCriteria(Criteria.where("isDeleted").is(false));

        List<CommentParent> allCommentParents = mongoTemplate.find(query, CommentParent.class);

        //查所有帖子并赋值评论点赞数
        for (CommentParent commentParent : allCommentParents) {
            String hashKey = COMMENT_PARENTCOMMENT + commentParent.getId();
            Integer likes = (Integer) redisTemplate.opsForHash().get(hashKey, _LIKE);
            commentParent.setLikes(likes);
        }
        //对评论点赞数进行排序
        allCommentParents.sort((o1, o2) -> {
            int likesComparison = Integer.compare(o2.getLikes(), o1.getLikes());
            if (likesComparison == 0) {
                return o1.getGmtCreate().compareTo(o2.getGmtCreate());
            }
            return likesComparison;
        });
        //计算分页的起始和结束索引
        int start = (page - 1) * limit;
        int end = Math.min(start + limit, allCommentParents.size());
        List<CommentParent> pageCommentParents = allCommentParents.subList(start, end);

        String setKey = COMMENT_PARENTCOMMENT_USER_LIKE + userId;
        for (CommentParent commentParent : pageCommentParents) {
            String hashKey = COMMENT_PARENTCOMMENT + commentParent.getId();
            getInfo(commentParent, setKey, hashKey);      //获取评论详细信息

        }
        //取缓存 遍历查下面方法
        //TODO 从getInfo提取方法,查询用户是否点赞/收藏
        PageResult pageResult = new PageResult((long) allCommentParents.size(), allCommentParents.size(), pageCommentParents, page);
        return pageResult;
    }

    /**
     * 获取评论相关信息
     * ，如评论数量，点赞量，是否点赞过，用户信息等
     *
     * @param commentParent 评论
     * @param setKey
     * @param hashKey
     */
    private void getInfo(CommentParent commentParent, String setKey, String hashKey) {
        String parentUserId = commentParent.getUserId();
        String parentId = commentParent.getId();
//查询评论发布者信息
        CompletableFuture<UserInfoVo> userFuture = CompletableFuture.supplyAsync(() -> {
            try {
                UserInfoVo user = JSON.parseObject(JSON.toJSONString(userClient.getUserInfoById(parentUserId).getData().get("user")), UserInfoVo.class);
                if (user == null) {
                    throw new BaiYunException(ResultCode.ERROR, MessageConstant.QUERY_USERINFO_FAIL);
                }
                return user;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, threadPoolExecutor);
//查询子评论数量
        CompletableFuture<Integer> commentsCountFuture = CompletableFuture.supplyAsync(() -> {
            Query query = new Query();
            query.addCriteria(Criteria.where("ppCommentId").is(parentId));
            query.addCriteria(Criteria.where("isDeleted").is(false));
            return Math.toIntExact(mongoTemplate.count(query, CommentSon.class));
        }, threadPoolExecutor);
//查询评论点赞数量
        CompletableFuture<Integer> likesCountFuture = CompletableFuture.supplyAsync(() -> {
            return (Integer) redisTemplate.opsForHash().get(hashKey, _LIKE);
        }, threadPoolExecutor);
//查询是否点赞
        CompletableFuture<Boolean> isLikedFuture = CompletableFuture.supplyAsync(() -> {
            if (StringUtils.isEmpty(setKey)) {
                return false;
            }
            return redisTemplate.opsForSet().isMember(setKey, parentId);
        }, threadPoolExecutor);

        CompletableFuture.allOf(userFuture, commentsCountFuture, likesCountFuture, isLikedFuture).join();

        try {
            UserInfoVo user = userFuture.get();
            commentParent.setUserUseTitle(user.getTitles());
            commentParent.setUserName(user.getNickname());
            commentParent.setUserAvatar(user.getAvatar());
            commentParent.setIsJoin(user.getIsJoin());

            commentParent.setComments(commentsCountFuture.get());
            commentParent.setLikes(likesCountFuture.get());
            commentParent.setIsLiked(isLikedFuture.get());
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

}
